//------------------------------------------------------------------------------
// <copyright company="Telligent Systems">
//     Copyright (c) Telligent Systems Corporation.  All rights reserved.
// </copyright> 
//------------------------------------------------------------------------------

using System;
using System.Collections;
using System.Data;
using System.IO;
using System.Xml;
using CommunityServer.Components;
using CommunityServer.Configuration;

namespace CommunityServer.Blogs.Components
{
	/// <summary>
	/// Summary description for WeblogDataProvider.
	/// </summary>
    public abstract class WeblogDataProvider
    {
        public static readonly string WeblogDataProviderName = "WeblogDataProvider";

        #region Search
        public abstract PostSet SearchReindexPosts (int setsize, int settingsID);
		public abstract ThreadSet SearchIndexPosts (int setsize, BlogThreadQuery query);
			#endregion

        #region Instance

        private static WeblogDataProvider _defaultInstance = null;

        static WeblogDataProvider()
        {
            CreateDefaultCommonProvider();
        }

        /// <summary>
        /// Returns an instance of the user-specified data provider class.
        /// </summary>
        /// <returns>An instance of the user-specified data provider class.  This class must inherit the
        /// CommonDataProvider interface.</returns>
        public static WeblogDataProvider Instance() 
        {
            return _defaultInstance;
        }

        public static WeblogDataProvider Instance (Provider dataProvider) 
        {
            WeblogDataProvider fdp = CSCache.Get(dataProvider.Name) as WeblogDataProvider;
            if(fdp == null)
            {
                fdp = DataProviders.Invoke(dataProvider) as WeblogDataProvider;
                CSCache.Max(dataProvider.Name,fdp);
            }
            return fdp;
        }

        /// <summary>
        /// Creates the Default CommonDataProvider
        /// </summary>
        private static void CreateDefaultCommonProvider()
        {
            // Get the names of the providers
            //
            CSConfiguration config = CSConfiguration.GetConfig();

            // Read the configuration specific information
            // for this provider
            //
            Provider sqlForumsProvider = (Provider) config.Providers[WeblogDataProviderName];

            // Read the connection string for this provider
            //
            
            _defaultInstance = DataProviders.CreateInstance(sqlForumsProvider) as WeblogDataProvider;
        }
        
        #endregion

        #region Base Methods

        #region Get Posts
        public abstract WeblogPost GetWeblogPost(int postID, bool includeCategories, bool isApproved);
        public abstract ThreadSet GetBlogThreads(BlogThreadQuery query);
        public abstract PostSet GetPosts(BlogThreadQuery query);
		public abstract PostSet GetThreadsTrackedByUser(int SectionID, int UserID);
        #endregion

        #region Posts
        public abstract BlogPostResults AddPost(WeblogPost post, User user, out int PostID);
        public abstract BlogPostResults UpdatePost(WeblogPost post, int editedBy);
        public abstract void DeletePost(int sectionID, int postID, int userID, BlogPostType blogPostType);
        #endregion

        #region GetBlogs
        public abstract Hashtable GetWeblogs();
        #endregion

        #region Permissions
        public abstract ArrayList GetBlogPermissions(int weblogID);
        #endregion

        public abstract ArrayList GetPostsByMonths(int BlogID);
		public abstract Hashtable GetPostsByMonth(int BlogID, DateTime Month);

        public abstract void UpdateRecentContent(int SettingsID);
		public abstract void DeleteStaleSpamComments(int SettingsID, int expirationDays);

        #endregion

        #region Helpers

        public static object ConvertCategoriesToXML(string[] Categories)
        {
            if(Categories == null || Categories.Length == 0)
                return DBNull.Value;

            StringWriter sw = new StringWriter();
            XmlTextWriter writer = new XmlTextWriter(sw);
            writer.WriteStartElement("Categories");
            foreach (string category in Categories)
            {
                writer.WriteElementString("Category", category);
            }
            writer.Close();
            return sw.ToString();
        }

        #endregion

        #region Populate

        #region Weblogs

        /// <summary>
        /// Populates an existing Weblog object
        /// </summary>
        public static void PopulateWeblogData(IDataReader dr, Weblog w)
        {
            CommonDataProvider.PopulateSectionFromIDataRecord(dr,w);

            w.MostRecentPostName = dr["MostRecentPostName"] as string;

            w.MostRecentArticleID = (int)dr["MostRecentArticleID"];
            w.MostRecentArticleDate = (DateTime)dr["MostRecentArticleDate"];
            w.MostRecentArticleAuthor = dr["MostRecentArticleAuthor"] as string;
            w.MostRecentArticleAuthorID = (int)dr["MostRecentArticleAuthorID"];
            w.MostRecentArticleName = dr["MostRecentArticleName"] as string;
			w.MostRecentArticleSubject = dr["MostRecentArticleSubject"] as string;
           
            w.PostCount = (int)dr["PostCount"];
            w.ArticleCount = (int)dr["ArticleCount"];
            w.TrackbackCount = (int)dr["TrackbackCount"];
            w.CommentCount = (int)dr["CommentCount"];
			w.DefaultLanguage = dr["DefaultLanguage"] as string;
        }

        #endregion



        public static WeblogPost PopulateWeblogPostContentFromDataRow(DataRow dr, DataRelation relationShip) 
        {
            //Is this all of the data we need?
            WeblogPost post = new WeblogPost();

            post.SectionID =                (int) dr["SectionID"];
            post.PostID =					(int) dr["PostID"];
            post.Replies =                (int) dr["Replies"];
            post.Views =                  (int) dr["TotalViews"];
			post.AggViews =				  (int) dr["AggViews"];
			post.ThreadID =               (int) dr["ThreadID"];
            post.Subject =                (string) dr["Subject"];
            post.Body =                   (string) dr["Body"];
			post.Username =					dr["PostAuthor"].ToString().Trim().Length > 0 ? (string) dr["PostAuthor"] : (string) dr["ThreadPostAuthor"];
			post.AuthorID =				  (int) dr["UserID"];
		    //populate the post UserID as well as the IThread AuthorID
            post.UserID =                 (int)dr["UserID"];
            post.PostDate =                 (DateTime)dr["PostDate"];
            post.ThreadDate =             (DateTime) dr["ThreadDate"];
            post.IsLocked =               (bool) dr["IsLocked"];
            post.FormattedBody =           dr["FormattedBody"] as string;

            post.IsApproved =             (bool) dr["IsApproved"];


            post.PostLevel =        (int) dr["PostLevel"];
            post.ParentID = (int) dr["ParentID"];

            post.PostConfig =              (BlogPostConfig) (int)dr["PostConfiguration"];
            post.BlogPostType =			(BlogPostType) dr["ApplicationPostType"];
			
			post.SpamScore = (int) dr["SpamScore"];
			post.PostStatus = (PostStatus) ((int) dr["PostStatus"]);
            post.UserHostAddress = dr["IPAddress"] as string;

			
			//posts from cs versions below 2.0 usertime might be null
			try{post.UserTime =               (DateTime) dr["UserTime"];}
			catch{post.UserTime =              post.PostDate;}


            post.Name =                    dr["PostName"] as string;

			post.RatingSum = (int)dr["RatingSum"];
			post.TotalRatings = (int)dr["TotalRatings"];

			post.Points = (int)dr["PostPoints"];
			post.PostMedia = (PostMediaType)dr["PostMedia"];

  
                post.AttachmentFilename = dr["AttachmentFileName"] as string;
                if(post.AttachmentFilename != null)
                    post.Attachment = CommonDataProvider.PopulatePostAttachmentMetaDataFromIDataRow(dr);
                
  
            SerializerData data = new SerializerData();
            data.Keys = dr["PostPropertyNames"] as string;
            data.Values = dr["PostPropertyValues"] as string;
            post.SetSerializerData(data);



            DataRow[] categories = dr.GetChildRows(relationShip);
            if(categories != null && categories.Length > 0)
            {
                post.Categories = new string[categories.Length];
                for(int i = 0; i<categories.Length; i++)
                {
                    post.Categories[i] = categories[i]["Name"] as string;
                }
            }

            return post;
        }

        public static WeblogPost PopulateWeblogEntryFromIDataReader(IDataReader reader)
        {
            return PopulateWeblogEntryFromIDataReader(reader,false);
        }

        public static WeblogPost PopulateWeblogEntryFromIDataReader(IDataReader reader, bool isTopLevel) 
        {
            WeblogPost post = new WeblogPost();
            post.SectionID =                (int) reader["SectionID"];
            post.PostID =					(int) reader["PostID"];
            post.Replies =                (int) reader["Replies"];
            post.Views =                  (int) reader["TotalViews"];
            post.AggViews =				  (int) reader["AggViews"];
            post.ThreadID =               (int) reader["ThreadID"];
            post.Subject =                (string) reader["Subject"];
            post.Body =                   (string) reader["Body"];
			post.Username =					reader["PostAuthor"].ToString().Trim().Length > 0 ? (string) reader["PostAuthor"] : (string) reader["ThreadPostAuthor"];
			post.AuthorID =				  (int) reader["UserID"];
		    //populate the post UserID as well as the IThread AuthorID
            post.UserID =                   (int)reader["UserID"];
            post.PostDate =                 (DateTime)reader["PostDate"];
            
            post.ThreadDate =             (DateTime) reader["ThreadDate"];
            post.IsLocked =               (bool) reader["IsLocked"];
            post.IsApproved =             (bool) reader["IsApproved"];
            post.FormattedBody =           reader["FormattedBody"] as string;

            post.PostLevel =        (int) reader["PostLevel"];
            post.ParentID =         (int) reader["ParentID"];

            post.PostConfig =              (BlogPostConfig) (int)reader["PostConfiguration"];
            post.BlogPostType =			(BlogPostType) (int)reader["ApplicationPostType"];
			
			//posts from cs versions below 2.0 usertime might be null
			try{post.UserTime =               (DateTime) reader["UserTime"];}
			catch{post.UserTime =              post.PostDate;}

            post.Name =                    reader["PostName"] as string;

            post.RatingSum = (int)reader["RatingSum"];
            post.TotalRatings = (int)reader["TotalRatings"];
            post.Points = (int)reader["PostPoints"];
			post.PostMedia = (PostMediaType) reader["PostMedia"];

        	
        	post.SpamScore = (int) reader["SpamScore"];
        	post.PostStatus = (PostStatus) ((int) reader["PostStatus"]);
            post.UserHostAddress = reader["IPAddress"] as string;
       	
            if(isTopLevel)
            {
                post.AttachmentFilename = reader["AttachmentFileName"] as string;
                if(post.AttachmentFilename != null)
                    post.Attachment = CommonDataProvider.PopulatePostAttachmentMetaDataFromIDataRecord(reader);
                
            }

            SerializerData data = CommonDataProvider.PopulateSerializerDataIDataRecord(reader, SerializationType.Post);
            post.SetSerializerData(data);

            return post;
        }



        #endregion

    }
}
